using System;
using System.Text;

namespace GA_ScreenScraper
{
    internal class ScreenScraper
    {
        public IntPtr parentWindowHandle;
        private string childControlClassName;
        private static string childControlContents;

        public delegate int Callback(IntPtr hWnd, IntPtr lparam);

        private Callback myCallBack;

        // Initializes the app with the window handle of the parent window
        // the parent window handle is required if we are searching for the child control by its class name
        public ScreenScraper(string parentWindowName, string parentWindowClass)
        {
            IntPtr hWnd = Win32.FindWindowEx(IntPtr.Zero, IntPtr.Zero, parentWindowClass, parentWindowName);
            SetParentWindowHandle(hWnd);
        }

        // Initializes the app with the window handle of the parent window
        // the parent window handle is required if we are searching for the child control by its class name
        public ScreenScraper(int parentWindowHandle)
        {
            SetParentWindowHandle(new IntPtr(parentWindowHandle));
        }

        // Sets the parent Window handle, and also initializes the callback method
        private void SetParentWindowHandle(IntPtr hWnd)
        {
            parentWindowHandle = hWnd;
            myCallBack = new Callback(FindChildWindowHandle);
        }


        // This method is called by the EnumChildWindows WIN32 method while enumerating
        // all the children of the specified parent window
        private int FindChildWindowHandle(IntPtr hWnd, IntPtr lparam)
        {
            StringBuilder formDetails = new StringBuilder(1024);
            Win32.GetClassName(hWnd, formDetails, 1024);
            string className = formDetails.ToString().Trim();
            
            // is this the child control we are looking for?
            if (className.Equals(childControlClassName, StringComparison.OrdinalIgnoreCase))
            {
                // read child control's content
                ChildWindowPtr = hWnd;
                GetControlContent((int) hWnd);
                // return 0 so that EnumChildWindows() stops enumerating the remaining child windows
                return 0;
            }

            // return 1 so that EnumChildWindows() continues enumerating the remaining child windows
            return 1;
        }
        public IntPtr ChildWindowPtr = IntPtr.Zero;
        // this method takes in the handle of a control, and returns its contents as string
        public static string GetControlContent(int hWnd)
        {
            IntPtr windowHandle = new IntPtr(hWnd);
            StringBuilder sb = new StringBuilder(1024);
            string className, txtContent;

            // get the specified control's  class name
            Win32.GetClassName(windowHandle, sb, 256);
            className = sb.ToString().Trim();

            if (className.Equals("ListBox", StringComparison.OrdinalIgnoreCase))
            {
                txtContent = ScrapeListBoxContent(windowHandle);
            }
            else
            {
                txtContent = ScrapeControlContent(windowHandle);
            }
            childControlContents = txtContent;
            return txtContent;
        }

        // this method takes in the handle of a control, and returns its contents as string
        // Used for Edit (textbox), Buttons and Static controls
        private static string ScrapeControlContent(IntPtr hWnd)
        {
            StringBuilder sb;
            // get the length of the current control text
            IntPtr size = Win32.SendMessage(hWnd, Win32.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
            sb = new StringBuilder(((int) size) + 1);
            // get the current control's contents as text
            Win32.SendMessage(hWnd, Win32.WM_GETTEXT, size, sb);

            return sb.ToString();
        }

        // this method takes in the handle of a control, and returns its contents as string
        // Used specifically for listbox controls
        private static string ScrapeListBoxContent(IntPtr hWnd)
        {
            StringBuilder sb = new StringBuilder();

            // get the number of items in the listbox
            int listCount = (int) Win32.SendMessage(hWnd, Win32.LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);

            for (int i = 0; i < listCount; i++)
            {
                // get the length of the current list item's text
                int textLength = (int) Win32.SendMessage(hWnd, Win32.LB_GETTEXTLEN, new IntPtr(i), IntPtr.Zero);

                StringBuilder item = new StringBuilder(textLength + 1);
                // get the current list item text
                Win32.SendMessage(hWnd, Win32.LB_GETTEXT, new IntPtr(i), item);

                sb = sb.Append(item + " , ");
            }

            return sb.ToString();
        }

        
        // This method is used when we dont have the window handle for a child control, but have its class name
        public string GetControlContent(string childControlClass)
        {
            if (parentWindowHandle == IntPtr.Zero)
            {
                throw new Exception(
                    "Could not find the parent window. Please make sure that the target application has been started.");
            }
            childControlClassName = childControlClass;
            childControlContents = null;

            // Enumerate all the child controls of this window, and check their class
            Win32.EnumChildWindows(parentWindowHandle, myCallBack, 0);

            // if no child control with the specified class name was found, throw an exception
            if (childControlContents == null)
            {
                throw new Exception("The selected Parent Window does not contain any child of the specified class.");
            }

            //return the contents of the specified control
            return childControlContents;
        }
    }
}